iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 21
1
Modern Web

Angular 全集中筆記系列 第 21

第 21 型 - 範本驅動表單 (Template-Driven Form)

  • 分享至 

  • xImage
  •  

在網頁應用程式中,提供表單讓使用者輸入資料是常見的需求;針對表單的開發,Angular 提供了範本驅動表單 (Template-Driven Form) 與響應式表單 (Reactive Form) 兩種開發方式。這一篇將利用範本驅動表單 (Template-Driven Form) 來實作待辦事項的查詢。

前置作業

實作前先修改 task-remote.service.ts 檔案,利用 json-server 提供的 API 來針對主旨與狀態進行查詢,並在 task-list.component.css 檔案加入查詢頁面所需的樣式。

@Injectable({
  providedIn: "root",
})
export class TaskRemoteService {
  private _url = "http://localhost:3000/tasks";

  constructor(private httpClient: HttpClient) {}

  getData(subject?: string, state?: number): Observable<Task[]> {
    const condition = [];
    if (subject) {
      condition.push(`subject_like=${subject}`);
    }
    if (state !== undefined) {
      condition.push(`state=${state}`);
    }
    const url = this._url + (condition.length === 0 ? "" : `?${condition.join("&")}`);
    return this.httpClient.get<Task[]>(url);
  }
}
.search {
  padding: 10px;
}

.search div {
  display: flex;
  justify-content: space-between;
}

.search div.input {
  margin-right: 10px;
  flex-grow: 1;
  display: flex;
}

.search div.input input {
  flex-grow: 1;
}

.search div.button * {
  margin-right: 4px;
}

利用雙向繫結 (Two-way binding) 實作主旨查詢

Angular 把應用程式區分成頁面與資料兩部份,即便在表單開發上也是如此,Angular 將表單分成表單模型與表單樣版兩個部分。而在範本驅動表單 (Template-Driven Form) 的開發上,主要著重於表單樣版的定義,由 Angular 產生所對應的表單模型。

在開發範本驅動表單 (Template-Driven Form) 前需要匯入 FormsModule 模組,故在 task.module.ts 加入此模組的匯入。

@NgModule({
  imports: [CommonModule, FormsModule, HttpClientModule],
  declarations: [
    TaskComponent,
    TaskStateColorDirective,
    TaskListComponent,
    TaiwanDatePipe,
  ],
  exports: [TaskComponent, TaskListComponent],
})
export class TaskModule {}

Angular 提供 NgModel 指令來監控如 <input><select> 等表單標籤,因此在 task-list.component.html 加入查詢功能,並將 ngModeltask-list.component.tssubject 屬性進行雙向繫結 (Two-way binding),就可以利用主旨進行查詢。

<div class="search">
  <div>
    <div class="input">
      <input type="text" [(ngModel)]="subject" placeholder="主旨" />
    </div>
    <div class="button">
      <button type="button" (click)="onSearch()">查詢</button>
    </div>
  </div>
</div>
export class TaskListComponent implements OnInit {
  tasks$: Observable<Task[]>;

  subject: string;

  constructor(private taskService: TaskRemoteService) {}

  ngOnInit(): void {
    this.tasks$ = this.taskService.getData();
  }

  onSearch(): void {
    this.tasks$ = this.taskService.getData(this.subject);
  }
}

NgModel

利用範本參考變數 (Template Reference Variables) 傳遞值實作查詢

除了針對 ngModel 進行雙向繫結 (Two-way binding),也可以在 <input> 設定一範本參考變數 (Template Reference Variables),並在查詢時將值傳遞至查詢方法內。

因此,將 task-list.component.html 中的 <input> 標籤加入名稱為 '#subject' 的範本參考變數 (Template Reference Variables),並將其值設為 ngModel;最後,再把此變數值傳入 onSearch() 方法內。

<div class="search">
  <div>
    <div class="input">
      <input type="text" #subject="ngModel" ngModel placeholder="主旨" />
    </div>
    <div class="button">
      <button type="button" (click)="onSearch(subject)">查詢</button>
    </div>
  </div>
</div>

由於 Angular 在 NgModel 指令中,設定了 'exportAs' 屬性為 'ngModel',以告知 Angular 要如何將範本參考變數 (Template Reference Variables) 連結至指令中,因此所傳入的 subject 變數為 NgModel 型別。需注意的是,此輸入表單標籤還是需要使用 NgModel 指令,否則會拋出例外。

export class TaskListComponent implements OnInit {
  tasks$: Observable<Task[]>;

  constructor(private taskService: TaskRemoteService) {}

  onSearch(subject: NgModel): void {
    this.tasks$ = this.taskService.getData(subject.value);
  }
}

利用 ViewChild 取得輸入對象實作查詢

另外,也可以在 task-list.component.ts 利用 ViewChild 裝飾器屬性來取得 #subject

export class TaskListComponent implements OnInit {
  @ViewChild("subject") subject: NgModel;

  tasks$: Observable<Task[]>;

  constructor(private taskService: TaskRemoteService) {}

  onSearch(): void {
    this.tasks$ = this.taskService.getData(this.subject.value);
  }
}

利用 NgForm 實作待辦事項查詢

若要利用範本驅動表單 (Template-Driven Form) 開發表單,會在頁面中使用 <form> 標籤,且在此標籤內的表單輸入標籤設定 name 屬性值。因此,在 task-list.component.html 加入主旨與狀態的查詢表單,並利用 submit 事件進行查詢。

<form class="search" #form="ngForm" (submit)="onSearch(form)">
  <div>
    <div class="input">
      <input type="text" name="subject" #subject="ngModel" ngModel placeholder="主旨" />
      <select name="status" #status="ngModel" ngModel>
        <option value="">事項狀態</option>
        <option value="0">未完成</option>
        <option value="1">進行中</option>
        <option value="2">已完成</option>
      </select>
    </div>
    <div class="button">
      <span>{{ form.value | json }}</span>
      <button type="submit">查詢</button>
    </div>
  </div>
</form>
export class TaskListComponent implements OnInit {
  tasks$: Observable<Task[]>;

  constructor(private taskService: TaskRemoteService) {}

  onSearch(form: NgForm): void {
    const { subject, status } = form.value;
    this.tasks$ = this.taskService.getData(subject, status);
  }
}

在上面頁面程式中,也將 #form 資料顯示出來,從此可以看出表單模型值是利用頁面輸入標籤的 name 屬性設定所產生的。

ngForm

結論

這一篇利用查詢的實作,說明了範本驅動表單 (Template-Driven Form) 的開發,實作程式碼放在 GitHub 中,接下來將針對在此開發方式下,說明如何進行相關的表單驗證。


上一篇
第 20 型 - 依賴注入 (Dependency Injection, DI)
下一篇
第 22 型 - 範本驅動表單 (Template-Driven Form) - 表單驗證
系列文
Angular 全集中筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言